/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/
//Promise有三种状态 分别为 成功（fulfilled） 失败（rejected） 等待（pending）
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
   //all方法
   static all (array) {
      let resultArr = [];//返回的值也是一个数组
      //解决array项中有异步的问题
      let index = 0;
      //返回的也是一个Promise 对象
      return new MyPromise ((resolve, reject) => {
         function addDataOfResultArr (key, value) {
            resultArr[key] = value;
            index++;
            if (array.length === index){
               resolve(resultArr);
            }
         }
         for (let i = 0; i < array.length; i++) {
            let current = array[i];
            if (current instanceof MyPromise) {//array项是一个Promise对象
               current.then(value => addDataOfResultArr(i, value), errMsg => reject(errMsg));
            } else {//array项是一个值
               addDataOfResultArr(i, array[i]);
            }
         }
      });
   }
   static resolve (value) {
      if (value instanceof MyPromise) {//value是Promise对象
         return value;
      } else {//value是普通值
         return new MyPromise(resolve => resolve(value))
      }
   }
   //Promise是一个类，在执行这个类的时候 需要传递一个执行器进去 执行器（executor）会立即执行
   constructor (executor) {
      //立即执行
      //如果执行的代码错误  返回错误
      try {
         executor (this.resolve, this.reject)
      } catch (err) {
         this.reject(err)
      }
   }
   //初始的状态为pending
   status = PENDING;
   //成功后的值：默认为undefined
   sucValue = undefined;
   //失败后的值：默认为undefined
   errMsg = undefined;
   //储存成功回调：默认为undefined -> then 方法可以多次被调用，默认为[]
   successCallback = [];
   //储存失败回调：默认为undefined -> then 方法可以多次被调用，默认为[]
   failCallback = [];
   //resolve 和 reject 函数是用来更改状态的 
   resolve = value => {
      if (PENDING !== this.status) return; //一旦状态确定就不可更改
      //resolve：pending -> fulfilled 
      this.status = FULFILLED;
      //修改成功的后值
      this.sucValue = value;
      //当宏任务调用完成后去调用微任务的时候（执行resolve 返回 successCallback）
      //如果successCallback存在就执行，并传递参数 -> this.successCallback为数组，循环调用
      //this.successCallback && this.successCallback(this.sucValue); ->
      while (this.successCallback.length) this.successCallback.shift()();
   }
   reject = errMsg => {
      if (PENDING !== this.status) return; //一旦状态确定就不可更改
      // reject：pending -> rejected
      this.status = REJECTED;
      //修改失败的原因
      this.errMsg = errMsg;
      //当宏任务调用完成后去调用微任务的时候（执行reject 返回 failCallback）
      //如果failCallback存在就执行  -> this.failCallbackk为数组，循环调用
      //this.failCallback && this.failCallback(this.errMsg); ->
      while (this.failCallback.length) this.failCallback.shift()(); 
   }
   /* then方法内部做的事情就是去判断状态，
				成功：调用成功的回调函数
				失败：调用失败的回调函数
			then 方法是被定义在原型对象中的
      then成功回调有一个参数，表示成功后的值
      then失败回调有一个参数，表示失败的原因 
   */
   then (successCallback, failCallback) {
      //如果参数不是函数，就将上面传下来的值继续往下传
      successCallback = successCallback ? successCallback : value => value;
      failCallback = failCallback ? failCallback : errObj => { throw errObj };
      /*then 方法需要链式调用：
         需要返回Promise对象
      */
     let resultPromise =  new MyPromise ((resolve, reject) => {
      //判断状态
      if (FULFILLED === this.status) {
         //在new Promise的过程中拿不到resultPromise，所有将异步执行resolvePromise函数
         setTimeout (() => {
            //successCallback 执行错误，需返回给下一个then方法
            try {
               let x = successCallback(this.sucValue);
               /* 判断 X 的值是普通值还是Promise对象
                  如果是普通值 直接调用resolve
                  如果是Promise对象 查看Promise对象返回的结果
                     再根据Promise对象返回的结果 决定调用resolve 还是调用reject
               */
               resolvePromise(resultPromise, x, resolve, reject);
            } catch (error) {
               reject(error);
            }
         }, 0);
      } else if(REJECTED === this.status) {
         //在new Promise的过程中拿不到resultPromise，所有将异步执行resolvePromise函数
         setTimeout (() => {
            //successCallback 执行错误，需返回给下一个then方法
            try {
               //传递失败的原因
               let x = failCallback(this.errMsg);
               /* 判断 X 的值是普通值还是Promise对象
                  如果是普通值 直接调用resolve
                  如果是Promise对象 查看Promise对象返回的结果
                     再根据Promise对象返回的结果 决定调用resolve 还是调用reject
               */
               resolvePromise(resultPromise, x, resolve, reject);
            } catch (error) {
               reject(error);
            }
         }, 0);
      } else {//异步情况处理
         /* 当前状态为pending，需要先将成功回调和失败回调临时储存起来
               定义两个属性分别来储存相应的回调：
                  then方法可以被多次调用 -> 属性应定义为数组
         */
        this.successCallback.push(() => {
            setTimeout (() => {
               //successCallback 执行错误，需返回给下一个then方法
               try {
                  let x = successCallback(this.sucValue);
                  /* 判断 X 的值是普通值还是Promise对象
                     如果是普通值 直接调用resolve
                     如果是Promise对象 查看Promise对象返回的结果
                        再根据Promise对象返回的结果 决定调用resolve 还是调用reject
                  */
                  resolvePromise(resultPromise, x, resolve, reject);
               } catch (error) {
                  reject(error);
               }
            }, 0);
        });
        this.failCallback.push(() => {
         setTimeout (() => {
            //successCallback 执行错误，需返回给下一个then方法
            try {
               //传递失败的原因
               let x = failCallback(this.errMsg);
               /* 判断 X 的值是普通值还是Promise对象
                  如果是普通值 直接调用resolve
                  如果是Promise对象 查看Promise对象返回的结果
                     再根据Promise对象返回的结果 决定调用resolve 还是调用reject
               */
               resolvePromise(resultPromise, x, resolve, reject);
            } catch (error) {
               reject(error);
            }
         }, 0);
        });
      }
     });
     return resultPromise;
   }
   //finally方法
   finally (callback) {
      return this.then (value => {
         return MyPromise.resolve(callback()).then(() => value);
      }, errObj => {
         return MyPromise.resolve(callback()).then(() => { throw errObj });
      })
   }
   //catch 方法
   catch (failCallback) {
      return this.then(undefined, failCallback);
   }
};

//解析x的值，并进行判断执行
var resolvePromise = (resultPromise, x, resolve, reject) => {
   if(resultPromise === x) {
      return reject(new TypeError('chaining cycle detected for promise #<promise>'));
   }
   if (x instanceof MyPromise) {//如果x是Promise对象
      //x.then(value => resolve(value), errMsg => reject(errMsg));
      x.then(resolve, reject)//简化上一行
   } else {//如果x是普通值
      resolve(x);
   }
};
//导出myPromise
module.exports = MyPromise;